﻿using System;
using System.Collections.Generic;
using System.Text;
using Gammar.Digger.Entity;
using Gammar.Digger.IDAL;
using Gammar.Digger.DALFactory;
using Gammar.Digger.SystemFramework;
using System.Threading;
using System.Xml;
namespace Gammar.Digger.BLL
{
    public class DataCollectService
    {
        private digger_pluginEntity _plugin;

        private plugin_run_statusEntity _runStatus;

        private int runStatusId = 0;

        private string _isEnableThread = ConfigUtility.GetAppSetting("IsEnableThread");

        private Encoding encode = null;

        /// <summary>
        /// 插件运行状态
        /// </summary>
        public enum Status
        {
            Running,
            Pausing,
            Stopped
        }

        public enum event_type
        {
            access,error
        }

        #region data fields
        string baseName = string.Empty;
        string tableUrl = string.Empty;
        string tableData = string.Empty;
        string tableComment = string.Empty;

        IDbHelper db = DataAccess.CreateDbHelper(ConnectionString.SqlServer_GPriceCollect_Data);

        Idigger_sourceData dbData = DataAccess.Createdigger_sourceData(ConnectionString.SqlServer_GPriceCollect_Data);
        Idigger_url dbUrl = DataAccess.Createdigger_url(ConnectionString.SqlServer_GPriceCollect_Data);
        Icomment_data dbComment = DataAccess.Createcomment_data(ConnectionString.SqlServer_GPriceCollect_Data);

        Iplugin_run_status run_status = DataAccess.Createplugin_run_status();
        Iplugin_run_log run_log = DataAccess.Createplugin_run_log();

        #endregion

        /// <summary>
        /// 本次采集详情页面URL列表;
        /// </summary>
        private List<string> _urlDetails;

        private List<string> _categoryUrls;

        private List<string> _subcategoryUrls;

        private Thread[] threads;

        /// <summary>
        /// 采集深度
        /// </summary>
        private int? _depth;

        /// <summary>
        /// 当前采集数
        /// </summary>
        private int currentCollectNumber=0;

        /// <summary>
        /// 待采集数据总数
        /// </summary>
        private int dataTotal = 0;

        /// <summary>
        /// 每线程运行数
        /// </summary>
        private int threadnumber = 0;

        private int threadTotal = 0;

        private int threadIndex = 0;

        public DataCollectService(digger_pluginEntity plugin,int sysId,int statusid)
        {
            _plugin = plugin;

            _depth = _plugin.dig_depth;
            baseName ="tb_"+ _plugin.site_id.ToString() + "_" + _plugin.plugin_id.ToString() + "_";
            tableUrl = baseName + "url";
            tableData = baseName + "data";
            tableComment = baseName + "comments";

            if (!string.IsNullOrEmpty(plugin.page_Encode))
            {
                encode = Encoding.GetEncoding(plugin.page_Encode);
            }

            runStatusId = statusid;

             _runStatus = new plugin_run_statusEntity();
             _runStatus.plugin_id = _plugin.plugin_id;
             _runStatus.start_time = DateTime.Now.Ticks;
             _runStatus.status = (int)Status.Running;
             _runStatus.sys_id = sysId;
             _runStatus.thread_number = _plugin.thread_number;
             _runStatus.description = "正在获取本次采集的有效url...";

            
        }

        /// <summary>
        /// 执行一个插件的采集
        /// </summary>
        /// <param name="plugin_id"></param>
        public void Collect()
        {
           
            run_status.Updatepartial(_runStatus,"status_id="+runStatusId);
            WriteAccessLog(_runStatus.description);

            #region 从网站读取


            Console.WriteLine("开始采集：" + _plugin.name + "......");


            //当到达最大采集数
            if (currentCollectNumber > _plugin.max_number && _plugin.max_number != 0)
            {
                WriteAccessLog(string.Format("插件限定采集数：{0}小于当前采集数{1},退出。",_plugin.max_number,currentCollectNumber));
                Thread.CurrentThread.Abort();
            }
            //获取开始页面代码
            WebHelper webHelper = new WebHelper();
            string startPage = webHelper.GetSource(_plugin.start_url, encode);

            //获取全部详情url
            GetAllDetailUrls(startPage);

       
            #endregion

            //不存在则创建数据表
            DataBaseInstance();

            #region DB读取
            //_urlDetails = GetUrlsFromDB();
            #endregion

            //清空db数据
            //2008.7.24 修改为清data表数据，url不执行清理
            //bool clearUrl = db.Truncate(tableUrl);
            bool clearData = db.Truncate(tableData);
            string cwData = clearData ? ">>clear content data   ok" : ">>clear content data   failed";

            WriteAccessLog(cwData);

            #region config thread 
            //配置参数
            dataTotal = _urlDetails.Count;

            if (_isEnableThread=="1")
            {
                threadnumber = (int)_plugin.thread_number;
                threadTotal = dataTotal / threadnumber;
                threads = new Thread[threadnumber];
            }

            WriteAccessLog("本次待采集数：" + dataTotal);
            _runStatus = new plugin_run_statusEntity();
            _runStatus.total_number=dataTotal;
            run_status.Updatepartial(_runStatus, "status_id="+runStatusId.ToString());
           
            #endregion

#if DEBUG
            LogUtility.WriteAccessLog("本次待采集数：" + dataTotal.ToString());
#endif
            

            #region test data 

            //for (int i = 0; i < threadnumber; i++)
            //{
            //    threadIndex = i;
            //    threads[i] = new Thread(new ThreadStart(Test));
            //    threads[i].Name = i.ToString();
            //    threads[i].Start();
            //    Console.WriteLine("采集线程-" + i + "-已启动");
            //}
       
            #endregion

            if (_isEnableThread =="1")
            {
                #region get pages data [thread]
                for (int i = 0; i < threadnumber; i++)
                {
                    threadIndex = i;
                    threads[i] = new Thread(new ThreadStart(GetPage));
                    threads[i].Name = i.ToString();
                    threads[i].Start();
                   
                    WriteAccessLog("采集线程-" + i + "-已启动");
                }

                for (int i = 0; i < threadnumber; i++)
                {
                    if (!threads[i].IsAlive)
                    {
                        WriteAccessLog(threads[i].Name + "ABORT！");
                        threads[i].Abort();
                    }
                }
                #endregion
            }
            else
            {
                GetPageSingleThread();
            }

            WriteAccessLog(string.Format("=======采集结束于{0}=======", DateTime.Now));
            _runStatus = new plugin_run_statusEntity();
            _runStatus.description = "本插件采集结束";
            _runStatus.end_time = DateTime.Now.Ticks;
            _runStatus.status = (int)Status.Stopped;
            run_status.Updatepartial(_runStatus, "status_id=" + runStatusId);
        }

        #region get urls

        /// <summary>
        /// 返回分类url
        /// </summary>
        /// <param name="startPage"></param>
        /// <returns></returns>
        private List<string> GetCategoryUrls(string startPage)
        {
            WebHelper webhelper = new WebHelper();
            return webhelper.FormatUrls(_plugin.start_url, webhelper.MathString(startPage, _plugin.list_url_rule));
        }

        /// <summary>
        /// 返回所有子分类url
        /// </summary>
        /// <param name="CategoryUrls"></param>
        /// <returns></returns>
        private List<string> GetSubCateogryUrls(List<string> CategoryUrls)
        {
            //全部子分类url
            List<string> reval = new List<string>();
            foreach (string url in CategoryUrls)
            {
                WebHelper webhelper = new WebHelper();
                string page = webhelper.GetSource(url, encode);
                //当前子分类url
                List<string> subUrls = webhelper.MathString(page, _plugin.list_url_rule);
                subUrls = webhelper.FormatUrls(_plugin.start_url, subUrls);
                reval.AddRange(subUrls);
            }
            return reval;

        }

        /// <summary>
        /// 获取所有详情页URL
        /// </summary>
        /// <param name="startPage"></param>
        /// <returns></returns>
        private List<string> GetDetailUrls(List<string> subCategoryUrls)
        {
            List<string> reval = new List<string>();
            foreach (string url in subCategoryUrls)
            {
                //获取详情页url
                WebHelper webhelper = new WebHelper();
                string page = webhelper.GetSource(url, encode);
                List<string> detailUrls = webhelper.MathString(page, _plugin.content_url_rule);
                detailUrls = webhelper.FormatUrls(_plugin.start_url, detailUrls);
                reval.AddRange(detailUrls);

                //获取所有下一页url
                List<string> nextUrl=new List<string>();
                GetNextPageDetailUrls(page,ref nextUrl);
                if (nextUrl.Count > 0)
                {
                    reval.AddRange(nextUrl);
                }
            }
            return reval;
        }

        /// <summary>
        /// 获取下一页详情URL
        /// </summary>
        /// <param name="startPage"></param>
        /// <returns></returns>
        private List<string> GetNextDetailUrls(string sourcePage)
        {
            List<string> reval = new List<string>();
         
                //获取详情页url
            WebHelper webhelper = new WebHelper();
            List<string> detailUrls = webhelper.MathString(sourcePage, _plugin.content_url_rule);
            detailUrls = webhelper.FormatUrls(_plugin.start_url, detailUrls);

            reval.AddRange(detailUrls);

            return reval;
        }

        /// <summary>
        /// 递归回去下一页的详细页url
        /// </summary>
        /// <param name="subCateogryPage"></param>
        /// <returns></returns>
        private void GetNextPageDetailUrls(string subCateogryPage,ref List<string> allNextUrls)
        {
            //获取页内的下一页链接url
            WebHelper webhelper = new WebHelper();
            List<string> reval = allNextUrls;

            if (!string.IsNullOrEmpty(_plugin.list_nextPage_rule))
            {
                List<string> nextUrl = webhelper.MathString(subCateogryPage, _plugin.list_nextPage_rule);
                nextUrl = webhelper.FormatUrls(_plugin.start_url, nextUrl);

                //如果页内存在下一页的链接，存贮详情url
                if (nextUrl.Count > 0)
                {
                    List<string> detail = GetNextDetailUrls(subCateogryPage);
                    if (detail.Count > 0)
                    {
                        reval.AddRange(detail);

                        //获取下一页的源文件
                        string nextPage = webhelper.GetSource(nextUrl[0], encode);
                        GetNextPageDetailUrls(nextPage, ref allNextUrls);
                    }

                }
            }

          
            //return reval;

        }

        /// <summary>
        /// 获取所有详情url
        /// </summary>
        /// <param name="startPage"></param>
        private void GetAllDetailUrls(string startPage)
        {
            //获取分类url
            switch (_depth)
            {
                case 1:
                    WebHelper webhelper = new WebHelper();
                    List<string> list = new List<string>();
                    list.Add(_plugin.start_url);
                   // _urlDetails = webhelper.MathString(startPage, _plugin.list_url_rule);
                   // _urlDetails = webhelper.FormatUrls(_plugin.start_url, _urlDetails);
                    _urlDetails = GetDetailUrls(list);
                   // List<string> nextUrls = new List<string>();
                   // GetNextPageDetailUrls(startPage,ref nextUrls);
                  //  _urlDetails.AddRange(nextUrls);
                    break;

                case 2:
                    WebHelper helper = new WebHelper();
                    List<string> sourceArea = helper.MathString(startPage, _plugin.list_area_rule);
                    if (sourceArea.Count>0)
                    {
                        _categoryUrls = GetCategoryUrls(sourceArea[0]);
                        _urlDetails = GetDetailUrls(_categoryUrls);
                    }


                    break;
                case 3:
                    _categoryUrls = GetCategoryUrls(startPage);
                    _subcategoryUrls = GetSubCateogryUrls(_categoryUrls);
                    _urlDetails = GetDetailUrls(_subcategoryUrls);

                    break;
                default:
                    break;
            }
        }

        #endregion

        private void GetNextPageDetailContent(string detailStartPage,ref StringBuilder sb)
        {
            WebHelper webhelper = new WebHelper();
            List<string> nextUrl = webhelper.MathString(detailStartPage, _plugin.content_nextPage_rule);
            if (nextUrl.Count>0&&!string.IsNullOrEmpty(nextUrl[0]))
            {
                string nextPage = webhelper.GetSource(nextUrl[0], encode);
                sb.Append(webhelper.MathString(nextPage, _plugin.content_detail_rule)[0].Replace("'", "''"));

                GetNextPageDetailContent(nextPage,ref sb);
            }
        }

        private void GetPage()
        {
           

            if (!Thread.CurrentThread.IsAlive)
            {
                Console.WriteLine(Thread.CurrentThread.Name +"is not alive now!!!!!!!!!!!!");
            }

            threadIndex = int.Parse(Thread.CurrentThread.Name);
            int start = threadIndex * threadTotal;
            int end = (threadIndex + 1) * threadTotal;
            for (int i = start; i < end; i++)
            {

#if DEBUG
                if (Thread.CurrentThread.Name=="1")
                {
                    Console.WriteLine("thread 1 is running...");
                }
                if (Thread.CurrentThread.Name=="2")
                {
                     Console.WriteLine("thread 2 is running...");
                }
#endif
                lock (this)
                {
                    currentCollectNumber++;

                    //判断当前采集是否大于限定总数
                    if (_plugin.max_number != 0 && currentCollectNumber > _plugin.max_number)
                    {
                        Thread.CurrentThread.Abort();
                    }
                    string url = _urlDetails[i];
                    bool isValid = false;
                    string urlPage = string.Empty;
                    WebHelper webhelper = new WebHelper();
                    if (!string.IsNullOrEmpty(url))
                    {
                        urlPage = webhelper.GetSource(url, encode);
                        isValid = !string.IsNullOrEmpty(urlPage);
                    }

                    //获取页面是有效的
                    if (isValid)
                    {
                        Console.WriteLine("++++++++++ start get data ++++++++++");
                        Console.WriteLine("Valid threadID    " + Thread.CurrentThread.Name + "    url:" + url);
                        try
                        {
                            string url_name = string.Empty;
                            string originalPrice = string.Empty;
                            string salePrice = string.Empty;
                            if (!string.IsNullOrEmpty(_plugin.content_title_rule))
                            {
                                url_name = webhelper.MathString(urlPage, _plugin.content_title_rule)[0].Replace("'", "''");
                            }
                            Console.WriteLine("Finished reading url_name:" + url_name);
                            if (!string.IsNullOrEmpty(_plugin.content_originalPrice_rule))
                            {
                                originalPrice = webhelper.MathString(urlPage, _plugin.content_originalPrice_rule)[0].Replace("'", "''");
                            }
                            Console.WriteLine("Finished reading originalPrice:" + originalPrice);
                            if (!string.IsNullOrEmpty(_plugin.content_salePrice_rule))
                            {
                                salePrice = webhelper.MathString(urlPage, _plugin.content_salePrice_rule)[0].Replace("'", "''");
                            }
                            Console.WriteLine("Finished reading salePrice:" + salePrice);
                            string CreateDate = string.Empty;
                            if (!string.IsNullOrEmpty(_plugin.content_CreateDate_rule))
                            {
                                CreateDate = webhelper.MathString(urlPage, _plugin.content_CreateDate_rule)[0].Replace("'", "''");
                            }
                            Console.WriteLine("Finished reading CreateDate:" + CreateDate);

                            string sb = GetContent(urlPage, webhelper);

                            Console.WriteLine("++++++++++ End get data ++++++++++");



                            #region save to database

                            Console.WriteLine(">>start to store into database     " + url);
                            digger_urlEntity diggerUrl = new digger_urlEntity();
                            diggerUrl.url = url;
                            diggerUrl.name = url_name;
                            diggerUrl.is_valid = isValid;
                            diggerUrl.url_id = Guid.NewGuid();
                            int result = dbUrl.Add(diggerUrl, tableUrl);

                            if (result == 1)
                            {
                                Console.WriteLine(">>save url success!");
                            }

                            digger_sourceDataEntity diggerData = new digger_sourceDataEntity();
                            diggerData.data_id = Guid.NewGuid();
                            diggerData.title = url_name;
                            diggerData.detail = sb;
                            diggerData.original_price = originalPrice;
                            diggerData.sale_price = salePrice;
                            diggerData.image = "";//TODO
                            diggerData.create_time = CreateDate;
                            diggerData.source_name = "";//TODO
                            diggerData.image_path = "";//TODO
                            diggerData.last_modify_time = StringHelper.DateTimeToLong(DateTime.Now);
                            diggerData.brand = "";//TODO
                            diggerData.url_id = diggerUrl.url_id;
                            result = dbData.Add(diggerData, tableData);

                            if (result == 1)
                            {
                                Console.WriteLine(">>save content success!");
                            }
                            Console.WriteLine("url:" + url + "   Finished------");

                            #endregion
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                            Console.WriteLine(ex.Source);

                        }
                    }
                }
            }
        }


        private void GetPageSingleThread()
        {
            WriteAccessLog("插件正在执行数据采集中...");

            threadIndex = 0;// int.Parse(Thread.CurrentThread.Name);
            int start = threadIndex * dataTotal;
            int end = (threadIndex + 1) * dataTotal;

            int success = 0;
            int failed = 0;
            for (int i = start; i < end; i++)
            {

                currentCollectNumber++;

                //判断当前采集是否大于限定总数
                if (_plugin.max_number != 0 && currentCollectNumber > _plugin.max_number)
                {
                    return;
                }
                string url = _urlDetails[i];
                bool isValid = false;
                string urlPage = string.Empty;
                WebHelper webhelper = new WebHelper();
                if (!string.IsNullOrEmpty(url))
                {
                    urlPage = webhelper.GetSource(url, encode);
                    isValid = !string.IsNullOrEmpty(urlPage);
                }

                //获取页面是有效的
                if (isValid)
                {
                    Console.WriteLine("++++++++++ start get data ++++++++++");
                   // Console.WriteLine("Valid threadID    " + Thread.CurrentThread.Name + "    url:" + url);
                    // Console.WriteLine("url is valid :"+url);
                    try
                    {
                        string url_name = string.Empty;
                        string originalPrice = string.Empty;
                        string salePrice = string.Empty;
                        if (!string.IsNullOrEmpty(_plugin.content_title_rule))
                        {
                            url_name = webhelper.MathString(urlPage, _plugin.content_title_rule)[0].Replace("'", "''");
                        }
                        Console.WriteLine("Finished reading url_name:" + url_name);
                        if (!string.IsNullOrEmpty(_plugin.content_originalPrice_rule))
                        {
                            originalPrice = webhelper.MathString(urlPage, _plugin.content_originalPrice_rule)[0].Replace("'", "''");
                        }
                        Console.WriteLine("Finished reading originalPrice:" + originalPrice);
                        if (!string.IsNullOrEmpty(_plugin.content_salePrice_rule))
                        {
                            salePrice = webhelper.MathString(urlPage, _plugin.content_salePrice_rule)[0].Replace("'", "''");
                        }
                        Console.WriteLine("Finished reading salePrice:" + salePrice);
                        string CreateDate = string.Empty;
                        if (!string.IsNullOrEmpty(_plugin.content_CreateDate_rule))
                        {
                            CreateDate = webhelper.MathString(urlPage, _plugin.content_CreateDate_rule)[0].Replace("'", "''");
                        }
                        Console.WriteLine("Finished reading CreateDate:" + CreateDate);

                        string content = GetContent(urlPage, webhelper);

                        Console.WriteLine("++++++++++ End get data ++++++++++");


                        #region save to database

                        Console.WriteLine(">>start to store into database     " + url);
                        digger_urlEntity diggerUrl = new digger_urlEntity();
                        diggerUrl.url = url;
                        diggerUrl.name = url_name;
                        diggerUrl.is_valid = isValid;
                        diggerUrl.url_id = Guid.NewGuid();
                        int result = dbUrl.Add(diggerUrl, tableUrl);

                        if (result == 1)
                        {
                            Console.WriteLine(">>save url success!");
                        }

                        digger_sourceDataEntity diggerData = new digger_sourceDataEntity();
                        diggerData.data_id = Guid.NewGuid();
                        diggerData.title = url_name;
                        diggerData.detail = content;
                        diggerData.original_price = originalPrice;
                        diggerData.sale_price = salePrice;
                        diggerData.image = "";//TODO
                        diggerData.create_time = CreateDate;
                        diggerData.source_name = "";//TODO
                        diggerData.image_path = "";//TODO
                        diggerData.last_modify_time = StringHelper.DateTimeToLong(DateTime.Now);
                        diggerData.brand = "";//TODO
                        diggerData.url_id = diggerUrl.url_id;
                        result = dbData.Add(diggerData, tableData);

                        if (result == 1)
                        {
                            Console.WriteLine(">>save content success!");
                        }
                        Console.WriteLine("url:" + url + "   Finished------");

                        #endregion
                        success++;
                    }
                    catch (Exception ex)
                    {
                        WriteErrorLog("url:" + url + "  error:" + ex.Message);
                        failed++;
                    }
                }
                else
                {
                    WriteErrorLog("无效url:" + url);
                    failed++;
                }
                _runStatus=new plugin_run_statusEntity();
                _runStatus.finished_number=currentCollectNumber;
                _runStatus.success_number=success;
                _runStatus.failed_number=failed;
                run_status.Updatepartial(_runStatus,"status_id="+runStatusId.ToString());
            }


        }
        /// <summary>
        /// 判断是否存在table，不存在则创建Table
        /// </summary>
        private void DataBaseInstance()
        {
           
            if (!db.IsExistTable(tableUrl))
            {
                db.CreateUrlTable(tableUrl);
            }
            if (!db.IsExistTable(tableData))
            {
                db.CreateDataTable(tableData);
            }
            if (!db.IsExistTable(tableComment))
            {
                db.CreateCommentsTable(tableComment);
            }

        }

        #region test method
        /// <summary>
        /// 保存详情内容
        /// </summary>
        /// <param name="url"></param>
        private void SaveContent(string url)
        { }
        private void SaveUrl()
        {
            foreach (string url in _urlDetails)
            {
                digger_urlEntity diggerUrl = new digger_urlEntity();
                diggerUrl.url = url;
                diggerUrl.name = "";
                diggerUrl.is_valid = true;
                diggerUrl.url_id = Guid.NewGuid();
                dbUrl.Add(diggerUrl, tableUrl);
            }
        
        }
        private List<string> GetUrlsFromDB()
        {
            List<string> reval = new List<string>();
            SortList<digger_urlEntity> myurls= dbUrl.GetList("",tableUrl);
            foreach (digger_urlEntity entity in myurls)
            {
                reval.Add(entity.url);
            }
            return reval;
        }

        private void Test()
        {
            threadIndex = int.Parse(Thread.CurrentThread.Name);
            int start = threadIndex * threadTotal;
            int end = (threadIndex + 1) * threadTotal;
            for (int i = start; i < end; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine("当前线程ID:" + Thread.CurrentThread.ManagedThreadId + "---data:" + i);
            }
        }
        #endregion


        /// <summary>
        /// 获取详细情页的详细内容
        /// </summary>
        /// <param name="urlPage"></param>
        /// <param name="webhelper"></param>
        /// <returns></returns>
        private string GetContent(string urlPage,WebHelper webhelper)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(_plugin.content_detail_rule);

            XmlNode n = doc.SelectSingleNode("root");
            XmlNodeList nodeList = n.ChildNodes;

            foreach (XmlNode node in nodeList)
            {
                string rule = node.InnerText;
                try
                {
                    Console.WriteLine("Reading :" + node.Name);
                    string mathedString=string.Empty;
                    List<string> mathedList = webhelper.MathString(urlPage, rule);
                    if (mathedList.Count>0)
                    {
                        mathedString = mathedList[0].Replace("'", "''");
                    }
                    
                    if (node.Name=="content")
                    {
                        StringBuilder sb = new StringBuilder();
                        GetNextPageDetailContent(urlPage, ref sb);

                        node.InnerXml = "<![CDATA[" + mathedString + sb.ToString() + "]]>";
                    }
                    else
                    {
                        node.InnerXml = "<![CDATA[" + mathedString + "]]>";
                    }
                }
                catch (Exception ex)
                {
                    node.InnerXml = "<![CDATA[]]>";
                    Console.WriteLine("Error:read page detail info"+ex.Message+"\n" + ex.StackTrace);
                }
            }

            return doc.InnerXml;

        }


        /// <summary>
        /// 写运行日志到数据库和屏幕
        /// </summary>
        /// <param name="message"></param>
        private void WriteAccessLog(string message)
        {
            run_log.Add(new plugin_run_logEntity(null, (int)event_type.access, message, DateTime.Now.Ticks, runStatusId));
            Console.WriteLine(message);
        }

        /// <summary>
        /// 写错误日志到数据库和屏幕
        /// </summary>
        /// <param name="message"></param>
        private void WriteErrorLog(string message)
        {
            run_log.Add(new plugin_run_logEntity(null, (int)event_type.error, message, DateTime.Now.Ticks, runStatusId));
            ConsoleColor color = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(message);
            Console.ForegroundColor = color;
        }
    }
}
